
	
	.globl _i2c_init		;global function for initialisation 
	.globl _i2c_read		;global function to initiate i2c read
	.globl _i2c_write		;global function to initiate i2c write
	.globl _i2c_sendData		;global function to write data
	.globl _i2c_readData		;global function to read data
	.globl _i2c_stop		;global function to issue stop command
	.globl _i2c_ack			;global function to issue ack command
	.globl _i2c_noack		;global function to issue nack command
	.globl _i2c_expandinit		;global function to initiate io expander
	.globl _i2c_reset
	
	;SCL is P1.0 and SDA is P1.1
	.area CSEG			;start of code segment

				

_i2c_write0:				;sending 0 on the SDA line		
		CLR	P1.1
		NOP
		SETB	P1.0
		NOP
		NOP
		NOP
		NOP	
		NOP
		NOP
		NOP
		CLR	P1.0
		NOP
		;end of 0
		RET



_i2c_write1:				;sending 1 on the SCL Line
		SETB	P1.1
		NOP
		SETB	P1.0
		NOP
		NOP
		NOP
		NOP	
		NOP
		NOP
		NOP
		CLR	P1.0
		CLR	P1.1
		;end of 1
		RET



_i2c_start: 	SETB	P1.1		;Generate Start Condition
		NOP
		NOP
		SETB	P1.0		
		NOP
		NOP
		NOP
		CLR	P1.1		;bring SDA low when SCL is high to signal START
		NOP
		NOP	
		NOP
		CLR	P1.0
		NOP
		NOP
					;end of start
		ret

_i2c_stop:					
		NOP			;guarantee bus free time
		CLR	P1.1
		NOP
		NOP
		NOP
		NOP
		NOP
		NOP
		SETB	P1.0		;Generate Stop Condition, set SDA when SCL is high
		NOP
		NOP	
		NOP
		SETB	P1.1
		NOP
		NOP
		NOP
		CLR	P1.0
		NOP
		NOP
					 ;end of start
		RET



_i2c_ack:			;issues acknowledge command, returns 1 on success, 0 on ack failure, issued on 9th SCL clock pulse
	
	push 	_bp		;push existing stack fram pointer value in stack
	mov 	_bp,sp 		;stack contains the return address, save it into stack frame pointer	
	NOP
				
	SETB	P1.1		;set SDA line, ie release SDA line 	
	NOP
	SETB	P1.0		;rising pulse of SCL
	JNB	P1.1,ack	;checks if slave device has pulled SDA line low to signal ackowledge
	MOV	r4,#01		
	SJMP	resume
ack:	MOV	r4,#00	
	SJMP end
resume:	NOP
	NOP
end:	CLR	P1.0		;end of SCL clock pulse
	mov	dpl,r4		;Return 1 if positive acknoledge, else 0
	pop 	_bp		;get return address
	ret


_i2c_noack:			;issue no-acknowledge condition
	NOP
	CLR 	P1.1		;clear SDA line, ie do not release SDA line
	NOP
	SETB	P1.0		;start of SCL clock
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	CLR	P1.0		;end of SCL clock 
	NOP
	NOP
	NOP
	SETB	P1.1		;release SDA
	NOP
	RET	







_i2c_init:				;initiates I2C by sending START condition,device identifier and page block select bits
		push 	_bp		;push existing stack fram pointer value in stack
		mov 	_bp,sp 		;stack contains the return address, save it into stack frame pointer

		mov 	a,dpl 		;dpl contains the lower 8 bits of the leftmost variable

		mov 	r0,#03		;counter of 3 for sending block select bits
return1:	rr	a		;operation to invert block select bits, so as to sen MSB first
		djnz	r0,return1
		
		lcall _i2c_start	;send START condition
	
	
					;device code here 1010 for 24LC16B eprom
		lcall _i2c_write1
	
		lcall _i2c_write0

		lcall _i2c_write1

		lcall _i2c_write0
	
		
		
		mov 	r0,#03
					;B2 B1 B0 Sequence :
		
		clr	c
back1:		rlc	a
		jnc	send0
		lcall _i2c_write1
		sjmp	skip_send0
send0:		lcall _i2c_write0
skip_send0:	djnz	r0,back1		
		pop 	_bp		;get return address
		ret 			;return
		



_i2c_expandinit:			;function to initiate i2c link with io expander	
		push 	_bp		;push existing stack fram pointer value in stack
		mov 	_bp,sp 		;stack contains the return address, save it into stack frame pointer

		mov 	a,dpl 		;dpl contains the lower 8 bits of the leftmost variable

		
		
		lcall _i2c_start	;generate START Condition
	
	
					;device code here, 0100 for io expander
		lcall _i2c_write0
	
		lcall _i2c_write1

		lcall _i2c_write0

		lcall _i2c_write0
	
		
		
		mov 	r0,#03
					;A2 A1 A0 Sequence : 000 for the io expander
		
		lcall _i2c_write0
		lcall _i2c_write0
		lcall _i2c_write0
		
		pop 	_bp		;get return address
		ret 			;return
		



		

		





_i2c_read:				;sends the R/W bit as 1 in the control byte	
		

		lcall _i2c_write1
		lcall _i2c_ack
		RET
	


	


_i2c_write:				;sends the R/W bit as 1 in the control byte

		lcall _i2c_write0
		lcall _i2c_ack
		RET














_i2c_sendData:				;function transfers 1 byte serially to slave device
		push 	_bp		;push existing stack fram pointer value in stack
		mov 	_bp,sp 		;stack contains the return address, save it into stack frame pointer

		mov 	a,dpl 		;dpl contains the lower 8 bits of the leftmost variable

		mov 	r0,#08		;counter of 8 for 1 byte data transfer

		clr	c
back1W:		rlc	a		;rotate 1 bit into carry for single bit transfer
		jnc	send0W		;if bit is 0, initiate to write 0 on the SDA line
		lcall _i2c_write1	;else initiate write 1 on the SDA line
		sjmp	skip_send0W
send0W:		lcall _i2c_write0
skip_send0W:	djnz	r0,back1W
		lcall _i2c_ack		;issue ACK command on the 9th clock cycle
		MOV	dpl,r4		;function returns 1 on postive acknowledge from device
		pop 	_bp		;get return address
		ret 			;return
		

		

			

_i2c_readData:				;function reas 1 byte serially from slave device

		push 	_bp		;push existing stack fram pointer value in stack
		mov 	_bp,sp 		;stack contains the return address, save it into stack frame pointer
		
	
		mov 	r0,#08		;counter of 8 for 1 byte data transfer	

		mov	a,#00		;clear accumulator to prepare for data read

		clr	c		;clear carry to ensure bits received correctly
	;sending sca-0
	
backR:		nop
		setb P1.0		;raise SCL high to start bit read
		nop
		jnb  P1.1,recvd0	;check if device has written a 0 or 1 on the SDA line
		setb	c		;set carry if 1 is read
		rlc	a		;rotate bit into accumulator
		sjmp	resumeR		;skip received 0 sequence
recvd0:		clr	c		;clear carry if 0 is received
		rlc	a		;rotate bit into accumulator
		nop
		nop
resumeR:	CLR	P1.0		;end of 1 clock pulse on SCL	
		nop	
		nop
		nop
		nop
		djnz	r0,backR	;loop back 8 times for 1 byte
		mov	dph,#00
		mov	dpl,a		;return received data byte via dpl
		pop 	_bp		;get return address
		ret
	
	
_i2c_reset:	push 	_bp		;push existing stack fram pointer value in stack
		mov 	_bp,sp 		;stack contains the return address, save it into stack frame pointer

		lcall _i2c_start	;send START
		lcall _i2c_write1	; write 1
		lcall _i2c_write1	; write 1
		lcall _i2c_write1	; write 1
		lcall _i2c_write1	; write 1
		lcall _i2c_write1	; write 1
		lcall _i2c_write1	; write 1
		lcall _i2c_write1	; write 1
		lcall _i2c_write1	; write 1
		lcall _i2c_write1	; write 1
					;9 1 bit sent
		lcall _i2c_start		;start again
		lcall _i2c_stop		;send stop
		pop 	_bp		;get return address
		ret
